package com.yst.sqlbuilder;

import com.yst.lambda.TableFieldFunc;

import java.util.Collection;
import java.util.Date;
import java.util.Objects;

public class SQLSelectCondition<T> extends SQLCondition<T> {
    public SQLSelectCondition(SQLSelect<T> select) {
        super(select);
    }

    @Override
    public SQLSelectCondition<T> compare(TableFieldFunc<T, ?> field, Symbol symbol, Object value) {
        super.compare(field, symbol, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> equal(TableFieldFunc<T, ?> field, Object value) {
        super.equal(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> notEqual(TableFieldFunc<T, ?> field, Object value) {
        super.notEqual(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> less(TableFieldFunc<T, ?> field, Object value) {
        super.less(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> lessEqual(TableFieldFunc<T, ?> field, Object value) {
        super.lessEqual(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> more(TableFieldFunc<T, ?> field, Object value) {
        super.more(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> moreEqual(TableFieldFunc<T, ?> field, Object value) {
        super.moreEqual(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> in(TableFieldFunc<T, ?> field, Collection<?> values) {
        super.in(field, values);
        return this;
    }

    @Override
    public SQLSelectCondition<T> between(TableFieldFunc<T, Number> field, Number value1, Number value2) {
        super.between(field, value1, value2);
        return this;
    }

    @Override
    public SQLSelectCondition<T> between(TableFieldFunc<T, Date> field, Date value1, Date value2) {
        super.between(field, value1, value2);
        return this;
    }

    @Override
    public SQLSelectCondition<T> between(TableFieldFunc<T, ?> field, SQLParam<?> value1, SQLParam<?> value2) {
        super.between(field, value1, value2);
        return this;
    }

    @Override
    public SQLSelectCondition<T> in(TableFieldFunc<T, ?> field, Object... values) {
        super.in(field, values);
        return this;
    }

    public SQLSelectCondition<T> inSelect(TableFieldFunc<T,?> field, ISQLSelect subSelect){
        subSelect.setParentSelect(getSelect());
        expressionList.add(new SQLFieldIn<>(getParentSelect(), field).setSelect(subSelect));
        return this;
    }

    @Override
    public SQLSelectCondition<T> like(TableFieldFunc<T, String> field, String value) {
        super.like(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> likeLeft(TableFieldFunc<T, String> field, String value) {
        super.likeLeft(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> likeRight(TableFieldFunc<T, String> field, String value) {
        super.likeRight(field, value);
        return this;
    }

    @Override
    public SQLSelectCondition<T> append(SQLCondition<T> condition) {
        super.append(condition);
        return this;
    }

    @Override
    public SQLSelectCondition<T> setLinkMode(LinkMode linkMode) {
        super.setLinkMode(linkMode);
        return this;
    }

    public SQLSelect<T> getSelect(){
        if (getParentSelect() instanceof SQLSelect){
            return (SQLSelect<T>) getParentSelect();
        }
        return null;
    }



    public static class SubSQLCondition<T> extends SQLSelectCondition<T> {
        SubSQLCondition(SQLSelectCondition<T> parent,LinkMode linkMode){
            super(parent.getSelect());
            parentCondition=parent;
            this.linkMode=linkMode;
        }

        @Override
        public SubSQLCondition<T> compare(TableFieldFunc<T, ?> field, Symbol symbol, Object value) {
            return (SubSQLCondition<T>)super.compare(field, symbol, value);
        }

        @Override
        public SubSQLCondition<T> equal(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.equal(field, value);
        }

        @Override
        public SubSQLCondition<T> notEqual(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.notEqual(field, value);
        }

        @Override
        public SubSQLCondition<T> less(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.less(field, value);
        }

        @Override
        public SubSQLCondition<T> lessEqual(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.lessEqual(field, value);
        }

        @Override
        public SubSQLCondition<T> more(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.more(field, value);
        }

        @Override
        public SubSQLCondition<T> moreEqual(TableFieldFunc<T, ?> field, Object value) {
            return (SubSQLCondition<T>)super.moreEqual(field, value);
        }

        @Override
        public SubSQLCondition<T> in(TableFieldFunc<T, ?> field, Collection<?> values) {
            return(SubSQLCondition<T>) super.in(field, values);
        }

        @Override
        public SubSQLCondition<T> between(TableFieldFunc<T, Number> field, Number value1, Number value2) {
            return (SubSQLCondition<T>)super.between(field, value1, value2);
        }

        @Override
        public SubSQLCondition<T> between(TableFieldFunc<T, Date> field, Date value1, Date value2) {
            return (SubSQLCondition<T>)super.between(field, value1, value2);
        }

        @Override
        public SubSQLCondition<T> in(TableFieldFunc<T, ?> field, Object... values) {
            return (SubSQLCondition<T>)super.in(field, values);
        }

        @Override
        public SubSQLCondition<T> inSelect(TableFieldFunc<T, ?> field, ISQLSelect subSelect) {
            return (SubSQLCondition<T>)super.inSelect(field, subSelect);
        }

        @Override
        public SubSQLCondition<T> like(TableFieldFunc<T, String> field, String value) {
            return (SubSQLCondition<T>)super.like(field, value);
        }

        @Override
        public SubSQLCondition<T> likeLeft(TableFieldFunc<T, String> field, String value) {
            return (SubSQLCondition<T>)super.likeLeft(field, value);
        }

        @Override
        public SubSQLCondition<T> likeRight(TableFieldFunc<T, String> field, String value) {
            return (SubSQLCondition<T>)super.likeRight(field, value);
        }

        public SQLSelectCondition<T> getParent() {
            return (SQLSelectCondition<T>)parentCondition;
        }

        public SQLSelectCondition<T> getRoot(){
            SQLSelectCondition<T> result=getParent();
            while(Objects.nonNull(result)){
                if (result instanceof SubSQLCondition) {
                    result = ((SubSQLCondition)result).getParent();
                }
            }
            return result;
        }

    }


    /**
     * append a SQLCondition in this condition and return sub sql condition
     * @param linkMode link mode
     * @return sub sql condition
     */
    public SubSQLCondition<T> append(LinkMode linkMode){
        SubSQLCondition<T> result= new SubSQLCondition<T>(this,linkMode);
        expressionList.add(result);
        return result;
    }

    public SubSQLCondition<T> or(){
        return append(LinkMode.OR);
    }

    public SubSQLCondition<T> and(){
        return append(LinkMode.AND);
    }
}
